package com.honghea.rxhttp.download;

import android.annotation.SuppressLint;
import android.os.Environment;
import android.util.Log;

import com.honghea.rxhttp.BuildConfig;
import com.honghea.rxhttp.DefaultRetrofitFactory;
import com.honghea.rxhttp.HttpConfig;
import com.honghea.rxhttp.RetryWhenNetworkException;
import com.honghea.rxhttp.download.api.DownloadApi;
import com.honghea.rxhttp.download.bean.DownloadInfo;
import com.honghea.rxhttp.download.file.FileUtil;
import com.honghea.rxhttp.exception.ApiException;
import com.honghea.rxhttp.exception.ExceptionEngine;


import java.io.File;
import java.io.IOException;
import java.util.concurrent.TimeUnit;


import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;

public class DownloadManager implements DownloadProgressListener {

    private static final String TAG = "DownloadManager";

    private static volatile DownloadManager mInstance;

    public static DownloadManager getInstance() {
        if (mInstance == null) {
            synchronized (DownloadManager.class) {
                if (mInstance == null) {
                    mInstance = new DownloadManager();
                }
            }
        }
        return mInstance;
    }

    private DownloadInfo info;

    private DownloadManager() {
        info = new DownloadInfo();
    }

    private Disposable subscribe;
    private DownloadApi api;


    public void startDownload(String url,File apkFile) {
        info.setUrl(url);
        info.setSavePath(apkFile.getAbsolutePath());

        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .connectTimeout(5, TimeUnit.SECONDS)
                .readTimeout(5,TimeUnit.SECONDS)
                .writeTimeout(5,TimeUnit.SECONDS);
        if (BuildConfig.DEBUG) {
            HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
            interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
            builder.addInterceptor(interceptor);
        }
        builder.addInterceptor(new HttpLoggingInterceptor());
        builder.addInterceptor(new DownloadInterceptor(this));

        OkHttpClient client = builder.build();
//        Retrofit retrofit = new DefaultRetrofitFactory().provide(client, HttpConfig.getInstance().getBASE_URL());
        //baseUrl无意义，只是为了不报错（baseurl不能为空的错误），实际我们用的@Url;
        Retrofit retrofit = new DefaultRetrofitFactory().provide(client, "https://honghea.oss-cn-hongkong.aliyuncs.com/");
        if (api == null) {
            api = retrofit.create(DownloadApi.class);
            info.setDownloadService(api);
        } else {
            api = info.getDownloadService();
        }

        download();
    }

    private void download() {
        subscribe = api.download(info.getUrl())
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .retryWhen(new RetryWhenNetworkException())
                .map(responseBody -> {
                    try {
                        FileUtil.write(responseBody, new File(info.getSavePath()), info);
                    } catch (IOException e) {
                        Log.e(TAG, "IOExection: " + e.getMessage());
                    }
                    return info;
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(
                        downloadInfo -> {
                            Log.d(TAG,"onNext");
                        },
                        throwable -> {
                            ApiException e = ExceptionEngine.exceptionHandler(throwable);
                            e.printStackTrace();
                            if (listener != null) {
                                listener.error(e);
                            }
                        },
                        () -> {
                            Log.d(TAG, "complete");
                            if (listener != null) {
                                listener.finish();
                            }
                        }
                );

    }


    @SuppressLint("CheckResult")
    @Override
    public void onProgressCallback(long read, long contentLength, boolean done) {
        if (info.getContentLength() > contentLength) {
            read = read + (info.getContentLength() - contentLength);
        } else {
            info.setContentLength(contentLength);
        }
        info.setReadLength(read);

        Observable.just(1).observeOn(AndroidSchedulers.mainThread()).subscribe(
                integer -> {
                    if (listener != null) {
                        listener.progress(info.getReadLength(), info.getContentLength(), done);
                    }
                }
        );
    }


    /*********************** 下载监听 *****************************/

    private ProgressListener listener;

    public void setListener(ProgressListener listener) {
        this.listener = listener;
    }

    public interface ProgressListener {
        void progress(long read, long contentLength, boolean done);

        void finish();

        void error(ApiException e);
    }
}

